Damit deine Programme nicht abstürzen:

Fehlerbehebung

# try · except · else · finally · raise · custom exceptions

# Klassiker: User-Eingabe robust abfangen
try:
x = int(input("Zahl: "))
print(f"Du hast {{"{x}"}} eingegeben")
except ValueError:
print("Das war keine gültige Zahl 😅")

Warum Fehlerbehandlung wichtig ist

Fehler passieren immer: falsche Eingaben, fehlende Dateien, Netzwerkprobleme oder Logikfehler. Gute Fehlerbehandlung sorgt dafür, dass dein Programm nicht einfach abstürzt, sondern kontrolliert reagiert (z.B. eine Meldung ausgibt, neu fragt oder sauber beendet).

🧠
Robust
Dein Code läuft weiter, auch wenn etwas schief geht.
🧹
Sauber
Ressourcen (Dateien, Verbindungen) werden korrekt geschlossen.
🔍
Debugbar
Du erkennst schneller, was schief lief – und wo.
💡
Fehlerbehandlung ist nicht dazu da, alle Fehler zu verstecken. Sie ist dazu da, Fehler kontrolliert zu behandeln und dem Nutzer sinnvolle Hinweise zu geben.

SyntaxError vs. Exceptions

Es gibt grob zwei Kategorien: Syntaxfehler (dein Code ist nicht gültig) und Exceptions (Fehler während das Programm läuft).

🚫
SyntaxError
Passiert vor dem Start. Beispiel: Doppelpunkt vergessen, Klammern falsch, Tippfehler.
if True
print("Oops")
# → SyntaxError: ':' fehlt
⚠️
Runtime-Exceptions
Passieren während das Programm läuft: falsche Eingabe, Datei nicht gefunden, Division durch 0 …
x = 10 / 0
# → ZeroDivisionError
Exception Wann? Beispiel
ValueError Wert passt nicht zum Typ/Format int("abc")
TypeError Falscher Typ in Operation "5" + 2
ZeroDivisionError Division durch 0 10/0
FileNotFoundError Datei existiert nicht open("x.txt")
KeyError Key fehlt im Dictionary d["x"]
IndexError Index außerhalb Liste lst[99]

try: Risiko · except: Reaktion

Mit try führst du Code aus, der schiefgehen kann. Wenn eine Exception auftritt, springt Python in den passenden except-Block.

try_except.py
try: a = int(input("Zahl A: ")) b = int(input("Zahl B: ")) print(f"Ergebnis: {{"{a/b}"}}") except ValueError: print("Bitte nur Zahlen eingeben.") except ZeroDivisionError: print("Division durch 0 ist nicht erlaubt.")
⚠️
Wichtig: Fang nicht einfach pauschal alles mit except: ab. Besser: konkrete Exceptions (z.B. ValueError). Sonst versteckst du echte Bugs.

else läuft nur, wenn kein Fehler passiert

Der else-Block ist super, wenn du Code trennen willst: try nur „gefährlich“, else nur „okay“.

try_else.py
try: x = int(input("Zahl: ")) except ValueError: print("Keine Zahl.") else: print(f"Quadrat: {{"{x*x}"}}")

finally läuft immer

Der finally-Block wird immer ausgeführt – egal ob Fehler oder nicht. Perfekt für Cleanup (Dateien schließen, Verbindungen beenden).

finally.py
f = None try: f = open("daten.txt", "r") content = f.read() print(content) except FileNotFoundError: print("Datei nicht gefunden.") finally: if f: f.close() # wird immer ausgeführt
💡
Noch besser als finally ist oft der Kontextmanager: with open(...). Der schließt die Datei automatisch.
with_open.py
try: with open("daten.txt", "r") as f: print(f.read()) except FileNotFoundError: print("Datei fehlt.")

Mehrere Exceptions elegant behandeln

Du kannst mehrere Exceptions entweder einzeln abfangen oder in einer Klammer zusammenfassen. Außerdem kannst du die Fehlermeldung in eine Variable speichern.

multi_except.py
try: x = int(input("Zahl: ")) y = 10 / x except (ValueError, ZeroDivisionError) as e: print(f"Fehler: {{"{e}"}}") else: print(f"10 / x = {{"{y}"}}")
🎯
Fang nur das ab, was du wirklich erwartest. Wenn du alles abfängst, merkst du Bugs später oder gar nicht.

Fehler bewusst auslösen

Mit raise kannst du selbst eine Exception auslösen – z.B. wenn eine Eingabe ungültig ist.

raise.py
def set_age(age): if age < 0: raise ValueError("Alter darf nicht negativ sein") return age try: print(set_age(-1)) except ValueError as e: print(f"Fehler: {{"{e}"}}")
📣
raise ist perfekt für Validierung. Du sagst damit: „So darf mein Programm nicht weiterarbeiten.“

Eigene Fehlerklassen erstellen

Manchmal willst du Fehler klarer benennen. Dann erstellst du eine eigene Exception. Das ist einfach eine Klasse, die von Exception erbt.

custom_exception.py
class LoginError(Exception): pass def login(username, password): if password != "1234": raise LoginError("Passwort falsch") return True try: login("basti", "0000") except LoginError as e: print(f"Login fehlgeschlagen: {{"{e}"}}")
🧩
Eigene Exceptions machen Code lesbarer: Statt „ValueError irgendwo“ hast du z.B. „LoginError“.

assert für Annahmen (Debug)

assert ist eine „Sicherheitsleine“: Du prüfst Annahmen im Code. Wenn sie falsch sind, gibt es eine AssertionError.

assert.py
def divide(a, b): assert b != 0, "b darf nicht 0 sein" return a / b print(divide(10, 2)) # 5.0
🔎
Hinweis: assert ist eher für Debug/Entwicklung. Für echte Nutzer-Eingaben ist raise + saubere Fehlerbehandlung oft besser.

Mini-Projekt: Zahlenrechner (robust)

Ziel: Ein kleiner Rechner, der wiederholt zwei Zahlen und einen Operator abfragt. Er soll nicht abstürzen, sondern sauber Fehler melden und neu fragen.

rechner_try_except.py
def read_int(prompt): while True: try: return int(input(prompt)) except ValueError: print("Bitte eine ganze Zahl eingeben.") def calc(a, op, b): if op == "+": return a + b if op == "-": return a - b if op == "*": return a * b if op == "/": if b == 0: raise ZeroDivisionError("Division durch 0") return a / b raise ValueError("Unbekannter Operator") while True: a = read_int("A: ") b = read_int("B: ") op = input("Operator (+ - * /) oder q: ") if op == "q": break try: res = calc(a, op, b) print(f"= {{"{res}"}}") except (ValueError, ZeroDivisionError) as e: print(f"Fehler: {{"{e}"}}")
🚀
Challenge: Erweitere den Rechner um Floats (Kommazahlen) und füge einen Modus hinzu, der die letzten 5 Ergebnisse speichert (Liste) – und dabei ebenfalls Fehler abfängt.
Weiter lernen

Stabiler Code = besserer Code. Mit Fehlerbehandlung bist du schon deutlich "Pro" unterwegs. Als nächstes passen super: Module & Pakete oder kleine Praxisprojekte.